package cn.wolfcode.luowowo.redis.service.impl;

import cn.wolfcode.luowowo.domain.Strategy;
import cn.wolfcode.luowowo.redis.service.IStrategyStatiesVORedisService;
import cn.wolfcode.luowowo.redis.util.RedisKeys;
import cn.wolfcode.luowowo.redis.vo.StrategyStatisVO;
import cn.wolfcode.luowowo.service.impl.StrategyServiceImpl;
import cn.wolfcode.luowowo.util.DateUtil;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 攻略统计数据redis的业务层
 */
@Service
public class StrategyStatiesVORedisServiceImpl implements IStrategyStatiesVORedisService {

    @Autowired
    private StringRedisTemplate template;

    @Autowired
    private StrategyServiceImpl strategyService;

    //攻略阅读量的统计
    @Override
    public void viewnumIncrease(String sid, int i) {
        //1.判断vo对象是否存在
        StrategyStatisVO vo = this.getStrategyStatisVo(sid);

        //2.执行阅读数+1的操作
        vo.setViewnum(vo.getViewnum() + i);

        //将修改的数据更新
        this.setStrategyStatisVo(vo);
    }

    //获取vo对象
    @Override
    public StrategyStatisVO getStrategyStatisVo(String sid) {
        //vo对象的key：strategy_statis_vo:sid
        String key = RedisKeys.STRATEGY_STATIS_VO.join(sid);
        StrategyStatisVO vo = null;
        if (!template.hasKey(key)) {
            //vo对象不存在Redis中,创建一个vo存进去
            Strategy strategy = strategyService.get(sid);
            vo = new StrategyStatisVO();
            BeanUtils.copyProperties(strategy, vo);
            vo.setStrategyId(sid);

            //需要将初始化数据设置到Redis中
            template.opsForValue().set(key, JSON.toJSONString(vo));
        } else {
            //vo对象已经存在
            String voStr = template.opsForValue().get(key);
            //解析成VO对象
            vo = JSON.parseObject(voStr, StrategyStatisVO.class);
        }
        return vo;
    }

    //更改Redis的viewnum
    @Override
    public void setStrategyStatisVo(StrategyStatisVO vo) {
        //更改
        String key = RedisKeys.STRATEGY_STATIS_VO.join(vo.getStrategyId());
        template.opsForValue().set(key, JSON.toJSONString(vo));
    }

    //统计评论数量
    @Override
    public void replynumIncrease(String strategyId, int i) {
        //1.获取vo
        StrategyStatisVO vo = this.getStrategyStatisVo(strategyId);

        //2.评论数量 + 1
        vo.setReplynum(vo.getReplynum() + 1);

        //3.更新
        this.setStrategyStatisVo(vo);
    }

    //攻略收藏： ret：true 收藏成功 ，false：取消收藏
    @Override
    public boolean favor(String sid, String uid) {

        //1.创建list专门存放用户收藏的攻略id
        //key：strategy_statis_vo:uid    站在用户的角度，list中存攻略id
        String listKey = RedisKeys.USER_STRATEGY_FAVOR.join(uid);

        List<String> list = null;
        if (template.hasKey(listKey)) {
            //list在Redis中已经存在，就获取到它
            String listStr = template.opsForValue().get(listKey);
            //将json字符串转换成list集合  参数2：list的泛型
            list = JSON.parseArray(listStr, String.class);
        } else {
            //list在Redis中还不存在，创建并初始化
            list = new ArrayList<>();
        }

        //判断攻略的id在list中是否已经存在
        StrategyStatisVO vo = this.getStrategyStatisVo(sid);
        if (!list.contains(sid)) {
            //2.用户发起请求，查看list中是否已经存在了这个攻略id，不存在表示收藏
            vo.setFavornum(vo.getFavornum() + 1);
            list.add(sid);//添加
        } else {
            //3.用户发起请求，查看list中是否已经存在了这个攻略id，存在表示取消收藏
            vo.setFavornum(vo.getFavornum() - 1);
            list.remove(sid);//移除
        }

        //4.更新数据
        template.opsForValue().set(listKey, JSON.toJSONString(list));//保存list
        this.setStrategyStatisVo(vo);//保存vo

        return list.contains(sid);//一顿操作之后，最后sid在list中，表示收藏成功，true
    }

    @Override
    public List<String> getSids(String uid) {
        //收藏攻略list的key设计成前缀 + uid，此时用到了
        String listKey = RedisKeys.USER_STRATEGY_FAVOR.join(uid);
        //要拿vo中的list，得先确定有没有，在分情况处理
        List<String> list = null;
        if (template.hasKey(listKey)) {
            //已经存在了
            String listStr = template.opsForValue().get(listKey);
            //将JSON格式的转换成List对象
            list = JSON.parseArray(listStr, String.class);
        } else {
            //不存在创建
            list = new ArrayList<>();
        }
        return list;
    }

    //点赞攻略
    @Override
    public boolean strategyThumbup(String sid, String uid) {
        //1.判断标记是否存在
        String signKey = RedisKeys.STRATEGY_THUMBUP.join(uid, sid);//key和攻略用户都有关系，一个用户可以顶多个不同的，一个一天只能一次
        if (!template.hasKey(signKey)) {
            //2.如果不存在就将标记添加进vo中的顶，存在Redis中，点赞数 + 1，设置有效时间，更新vo对象
            StrategyStatisVO vo = this.getStrategyStatisVo(sid);
            vo.setThumbsupnum(vo.getThumbsupnum() + 1);
            this.setStrategyStatisVo(vo);

            //设置时效性
            Date now = new Date();
            //`今天的最后一秒  - 当前时间`  （即距今天结束还有多久就活多久）
            Date endDate = DateUtil.getEndDate(now);
            long dateBetween = DateUtil.getDateBetween(now, endDate);
            template.opsForValue().set(signKey, "1", dateBetween, TimeUnit.SECONDS);
            return true;
        }
        //3.存在就是点赞失败，一天之只能点一次
        return false;
    }

    //判断攻略相关的统计参数在Redis中是否已经存在
    @Override
    public boolean isVoExist(String sid) {
        //通过key来看
        String key = RedisKeys.STRATEGY_STATIS_VO.join(sid);
        return template.hasKey(key);
    }

    //通过模板获取到匹配所有前缀一样的vo统计数据
    @Override
    public List<StrategyStatisVO> listStrategyVoByPattern(String pattern) {
        //拿到vo的key集合
        //strategy_statis_vo:*
        Set<String> keys = template.keys(pattern);
        //遍历keys拿到每一条数据，将数据添加进list中
        List<StrategyStatisVO> list = new ArrayList<>();
        if (keys != null) {//keys有东西才遍历
            for (String voKey : keys) {
                String voStr = template.opsForValue().get(voKey);
                //转换成对象，在添加
                list.add(JSON.parseObject(voStr, StrategyStatisVO.class));
            }
        }
        return list;
    }


}
